/*==============================================================================
                              Includes
==============================================================================*/
#include "hw_ints.h"
#include "hw_memmap.h"
#include "hw_types.h"
#include "debug.h"
#include "gpio.h"
#include "interrupt.h"
#include "sysctl.h"
#include "systick.h"
#include "ustdlib.h"
#include "uart.h"
#include "lm3s8962.h"
#include "uartstdio.h"
#include "rit128x96x4.h"
#include "main.h"
#include "timer.h"
/*==============================================================================
                              Defines
==============================================================================*/
#define SYSTICK_IN_SEC          ( 30 )

#define BUTTON_UP               ( 0x00000001 )

#define BUTTON_DOWN             ( 0x00000002 )

#define BUTTON_LEFT             ( 0x00000004 )

#define BUTTON_RIGHT            ( 0x00000008 )

#define BITMAP_HEADER_SIZE      ( 0x00000076 )

#define BITMAP_WIDTH_OFFSET     ( 0x00000012 )

#define BITMAP_HEIGHT_OFFSET    ( 0x00000016 )


/*==============================================================================
                              Error Routine
==============================================================================*/

#ifdef DEBUG
void
__error__(char *pcFilename, unsigned long ulLine)
{
}
#endif

/*==============================================================================
                           Initialize global variables
==============================================================================*/



 volatile tBoolean displayImage = 0x0;
 unsigned char * imagePtr;


/*==============================================================================
                        Local/Private Function Protoypes
==============================================================================*/
static void GPIO_fnInitButtons( void );
static void UART_fnInitDBG( void );
static void InitTimer ( unsigned short uiPeriodSec);
void drawBmpImage(unsigned char* imagePtr);
void delayTime(int timer1, int timer2);


/*==============================================================================
                           Function Definitions
==============================================================================*/

/*============================================================================*/
/*!

//fn  ISR_TimerHandler

\brief
    The interrupt service routine that is used as a timer

\param[in]
    Nothing

\return
    Nothing

\details
    This ISR handles the timer interrupt to switch the picture showing on the
    OLED display.

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
void ISR_TimerHandler( void )
{
    UARTprintf( "%d second is passed...\r\n", SYSTICK_IN_SEC );
    RIT128x96x4Clear();
    TimerIntClear(TIMER0_BASE, TIMER_TIMA_TIMEOUT);
    displayImage = ~displayImage;
    imagePtr = (displayImage == 0x0) ? (unsigned char *)&imageBaby[0] : \
             (unsigned char *)&imageJeep[0];
    drawBmpImage(imagePtr);
}

/*============================================================================*/
/*!

//fn  ISR_cbGpioEbuttHandler

\brief
    The interrupt service routine that handles button presses and start the
    timer.

\param[in]
    Nothing

\return
    Nothing

\details
    This ISR is triggered whenever an arrow button is pressed on the host device
    . A message is print to a destinated debug console according to which button 
    is pressed. Also when the left or right button is pressed, it will trigger 
    timer to count.

\code
REVISION HISTORY:

Version: 1.00    Date: 12-July-2012    By: Peter Hsiao & Li Xiang 
    - Created

\endcode

*/
/*============================================================================*/
void ISR_cbGpioEbuttHandler( void )
{
   unsigned long ulButt;
   
   
   // Reads the status of the button GPIO pins
   ulButt = (unsigned long) GPIOPinIntStatus( GPIO_PORTE_BASE, true);

   // Prints a message to the debug console according to the button pressed
   switch( ulButt )
   {
      case BUTTON_UP:
          UARTprintf( "Up\r\n" );
          
  /* Clear interrupt at the end of each press*/             
          GPIOPinIntClear(GPIO_PORTE_BASE,GPIO_PIN_0);
          break;
          
      case BUTTON_DOWN:
          UARTprintf( "Down\r\n" );
          
  /* Clear interrupt at the end of each press*/             
          GPIOPinIntClear(GPIO_PORTE_BASE,GPIO_PIN_1);
          break;
          
      case BUTTON_LEFT:
          UARTprintf( "Left\r\n" );
          
  /* Start the timer.*/
          InitTimer (SYSTICK_IN_SEC);
          
  /* Switch pics when button interrupt is detected*/
          RIT128x96x4Clear();
          displayImage = ~displayImage;
           imagePtr = (displayImage == 0x0) ? (unsigned char *)&imageBaby[0] : \
             (unsigned char *)&imageJeep[0];
          drawBmpImage(imagePtr);
      
  /* Clear interrupt at the end of each press*/        
          GPIOPinIntClear(GPIO_PORTE_BASE,GPIO_PIN_2);
          break;
          
            
      case BUTTON_RIGHT:
          UARTprintf( "Right\r\n" ); 
          
  /* Switch pics when button interrupt is detected*/ 
           InitTimer (SYSTICK_IN_SEC);
          RIT128x96x4Clear();
          displayImage = ~displayImage;
           imagePtr = (displayImage == 0x0) ? (unsigned char *)&imageBaby[0] : \
             (unsigned char *)&imageJeep[0];
          drawBmpImage(imagePtr);
          
 /* Clear interrupt at the end of each press*/    
          GPIOPinIntClear(GPIO_PORTE_BASE,GPIO_PIN_3);
          break;  
      
      default:
          UARTprintf( "Err...\r\n" ); 
          break;          
   }
}


void drawBmpImage(unsigned char* imagePtr)
{
	unsigned long ulRow, ulWidth, ulHeight;
	unsigned char *pucRow;

    //
    // Extract the width and height from the bitmap data.  These are encoded
    // in 4 byte fields but this application can't support images wider than
    // 128 pixels or taller than 80 rows so we merely read the least
    // significant byte.
    //
    ulHeight = (unsigned long)imagePtr[BITMAP_HEIGHT_OFFSET];
    ulWidth = (unsigned long)imagePtr[BITMAP_WIDTH_OFFSET];

    //
    // Display the BMP Image.
    //
    // The image is an ulWidth by ulHeight 4-bit gray scale image in BMP
    // format.  The divides by two are to account for the fact that there
    // are 2 pixels in each byte of image data.
    //

    //
    // Get a pointer to the first row of pixels in the image (which maps to the
    // bottom row on the display since bitmaps are encoded upside down).
    //
    pucRow = (unsigned char *)&imagePtr[BITMAP_HEADER_SIZE];

    for(ulRow = 0; ulRow < ulHeight; ulRow++)
        {
            //
            // Display in reverse row order.  We center the image horizontally on
            // the display.
            //
            RIT128x96x4ImageDraw(pucRow, 0,
                                 98-ulRow, ulWidth, 1);

            //
            // Move to the next row in the source image.
            //
            pucRow += (ulWidth / 2);
        }
}

void delayTime(int timer1, int timer2)
{
	int i = 0;
	int j = 0;
	for(i = 0; i < timer1; i++)
	{
		for(j = 0; j< timer2; j++)
		{

		}
	}
}

/*============================================================================*/
/*!

//fn  main

\brief
    The main fucntion

\param[in]
    Nothing

\return
    Nothing

\details

\code
REVISION HISTORY:

Version: 1.00    Date: 12-July-2012    By: Peter Hsiao & Li Xiang
    - Created

\endcode

*/
/*============================================================================*/

void main()
{
    volatile unsigned long ulLoop;

    // Set the clocking to run directly from the crystal.
    SysCtlClockSet(SYSCTL_SYSDIV_1 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN |
                   SYSCTL_XTAL_8MHZ);
  
    RIT128x96x4Init(1000000);
    
 /* Display the first image immediately*/ 
    imagePtr = (displayImage == 0x0) ? (unsigned char *)&imageBaby[0] : \
    (unsigned char *)&imageJeep[0];
          
    drawBmpImage(imagePtr);
    
    
    // Initialize and configure the UART pins for debugging on "hyperterminals"
    UART_fnInitDBG();
    
    // Initialize the timer that triggers every SYSTICK_IN_SEC seconds
    InitTimer (SYSTICK_IN_SEC);
   
    // Initialize and configure the GPIO pins for push buttons' interrupt
    GPIO_fnInitButtons();
    
    
    while(1)
    {        

    }
}

/*============================================================================*/
/*!

//fn  GPIO_fnInitButtons

\brief
    Initialize GPIO pins for arrow buttons on the host device

\param[in]
    Nothing

\return
    Nothing

\details

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
static void GPIO_fnInitButtons( void )
{
    // Enable the GPIO pin to read the arrow buttons.
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
    
    // Register interrupt service routine for GPIO on Port E
    GPIOPortIntRegister( GPIO_PORTE_BASE, ISR_cbGpioEbuttHandler );
    
    // Set Pin0 - Pin 3 on GPIO port E as input pins
    GPIOPinTypeGPIOInput( GPIO_PORTE_BASE,
                          GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 );

    // Config GPIO pad as examples indicated
    GPIOPadConfigSet( GPIO_PORTE_BASE,
                      GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3,
                      GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU );
    
    // Configure how the interrupts should be triggered (LOW_LEVEL in this case)
    GPIOIntTypeSet( GPIO_PORTE_BASE,
                    GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3,
                    GPIO_FALLING_EDGE );
    
    // Enable the GPIO Interrupt
    GPIOPinIntEnable( GPIO_PORTE_BASE, 
                      GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 );  
}

/*============================================================================*/
/*!

//fn  UART_fnInitDBG

\brief
    Initialize UART pins in order to output debug message on destinated debug
    console

\param[in]
    Nothing

\return
    Nothing

\details

\code
REVISION HISTORY:

Version: 1.00    Date: 05-July-2012    By: Peter Hsiao
    - Created

\endcode

*/
/*============================================================================*/
static void UART_fnInitDBG( void )
{
    // Enable the peripherals used by UART
    SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);    
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0);    
    
    // Set GPIO A0 and A1 as UART pins.
    GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
    // Configure the UART for 115,200, 8-N-1 operation.
    UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,
                        (UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                         UART_CONFIG_PAR_NONE));
    
    // Enable the UART feature    
    UARTEnable( UART0_BASE );
    
    // Initialize the UART so it can be used as a basic device for stdio
    UARTStdioInit( 0 );  
}

/*============================================================================*/
/*!

//fn  InitTimer

\brief
    Initialize the timer to send interrupt to processor every "uiPeriodSec"
    seconds.

\param[in]
    uiPeriodSec
        Number of seconds an interrupt is to be sent to CPU

\return
    Nothing

\details

\code
REVISION HISTORY:

Version: 1.00    Date: 12-July-2012    By: Li Xiang
    - Created

\endcode

*/
/*============================================================================*/

static void InitTimer ( unsigned short uiPeriodSec)
{
  //Register the timer interrupt.
  TimerIntRegister(TIMER0_BASE,TIMER_A,ISR_TimerHandler);
  
  //Configure the timer as a 32-bit one shot timer.
  TimerConfigure (TIMER0_BASE,TIMER_CFG_32_BIT_PER);
  
  // Set the interrupt period.
  TimerLoadSet(TIMER0_BASE,TIMER_A,SysCtlClockGet()*uiPeriodSec);
  
  // Enable timer and timer interrupt.
  TimerEnable (TIMER0_BASE,TIMER_A);
  TimerIntEnable (TIMER0_BASE,TIMER_TIMA_TIMEOUT);
  
}